/**
 * @file    diag_sys.c
 * @brief   系统类故障诊断
 * @author  Liuwei
 * @version 1.0.1
 * @date    2023-04-19
 * 
 * @copyright Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version   <th>Author   <th>Description
 * <tr><td>2023-04-19 <td>1.0.1     <td>Liuwei   <td>首次创建
 * </table>
 */

/* includes ------------------------------------------------------------------*/
#include "diagnosis.h"
#include "var_mng.h"
#include "event_mng.h"
#include "dev_afe.h"
#include "sample.h"
#include "diag_sys.h"
#include "param_mng.h"
#include "ctrl_mng.h"
#include "If_do.h"
#include "base_math.h"
/* macro/define --------------------------------------------------------------*/
#define DIAG_COL_DLY         (5000)
#define DIAG_TOL_DLY         (5000)
#define DIAG_SC_RCV_DLY      (60000)
#define DIAG_SC_LOCK_TIMES   (4) // 第一次开预充尝试，

#define FT_MOS_VOLT_DLY      (30000)
#define FT_MOS_VBUF_SIZE     (30)
#define FT_MOS_CURR_DLY      (10000)
#define FT_MOS_CBUF_SIZE     (10)
/* typedef -------------------------------------------------------------------*/

/* local functions -----------------------------------------------------------*/

/* static variables ----------------------------------------------------------*/
static diag_data_type diag_col = {0};
static diag_data_type diag_tol = {0};
static diag_data_type diag_sc = {0};
static diag_data_type diag_ft_cmos = {0};
static diag_data_type diag_ft_at_cmos = {0};
static diag_data_type diag_ft_dmos = {0};
static diag_data_type diag_soc_low = {0};
uint16_t diag_cmos_base_volt = 0;
uint16_t diag_dmos_base_volt = 0;
extern uint8_t wifi_send_flag;
/* global variables ----------------------------------------------------------*/

/** ------------------------------------------------------------------------- *
  *                             Global function
 ** ------------------------------------------------------------------------- */
/**
 * @brief 单体掉线诊断
 * @param  cylce:周期
 */
void diag_sys_col(uint16_t cylce)  
{
    uint16_t cell_ol_state = var_get_data(VAR_ID_CELL_OL_ST);

    if(0 == diag_col.prp_state)
    {
        if(0 != cell_ol_state)
        {
            diag_col.prp_time_cnt += cylce;
            if(diag_col.prp_time_cnt >= DIAG_COL_DLY)
            {
                diag_col.prp_state = 1;
                diag_col.prp_time_cnt = 0;
				event_add_to_sram(EVT_ID_FT_COL , cell_ol_state , 1);
				
				wifi_send_flag = 1;
            }
        }
        else
        {
            diag_col.prp_time_cnt = 0;
        }
    }
    else
    {
        if((0 == cell_ol_state)||(1 == var_get_data(VAR_ID_FAULT_CLEAR_STATE)))
        {
            diag_col.prp_state = 0;
			var_set_data(VAR_ID_FAULT_CLEAR_STATE , 0);
        }
    }
	
    diag_set_prp(PRP_ID_COL ,diag_col.prp_state );
}

/**
 * @brief  温度掉线诊断 - 
           电芯温度要掉线2个以上才上报故障，MOS和环境温度掉线任一一个上报故障
 * @param  cylce : 周期
 */
void diag_sys_tol(uint16_t cylce)
{
    uint16_t temp_ol_state = var_get_data(VAR_ID_TEMP_OL_ST);
	uint16_t mos_env_tol = 0;
	
	if(temp_ol_state & 0xC000)
		mos_env_tol = 1;
	
	temp_ol_state = math_get_data_bit1_num(temp_ol_state & 0x0FFF);
	
    if(0 == diag_tol.prp_state)
    {
        if((temp_ol_state > 1) || (mos_env_tol == 1))
        {
            diag_tol.prp_time_cnt += cylce;
            if(diag_tol.prp_time_cnt >= DIAG_TOL_DLY)
            {
                diag_tol.prp_state = 1;
                diag_tol.prp_time_cnt = 0;
				event_add_to_sram(EVT_ID_FT_TOL ,temp_ol_state , 1);
				
				wifi_send_flag = 1;
            }
        }
        else
        {
            diag_tol.prp_time_cnt = 0;
        }
    }
    else
    {
        if(((temp_ol_state <= 1) && (mos_env_tol == 0))||(1 == var_get_data(VAR_ID_FAULT_CLEAR_STATE)))
        {
            diag_tol.prp_state = 0;
			var_set_data(VAR_ID_FAULT_CLEAR_STATE , 0);
        }
    }

    diag_set_prp(PRP_ID_TOL ,diag_tol.prp_state );
}

/**
 * @brief  短路保护诊断
 * @param  cylce : 周期
 */
void diag_sys_sc(uint16_t cylce)
{
	uint8_t sys_state = 0;
	uint16_t sc_times = 0;
	sys_state = var_get_data(VAR_ID_CURR_DR);
    if(0 == diag_sc.prp_state)
    {
        if((1 == dev_afe_read_sc_alarm()) && (sample_set_sc_clr_state() == 0))
        {
			if(diag_sc.prp_con_times <= 2)
			{
				sample_restart_prechg(); // 第一次开预充尝试，
				sample_clr_sc_prp(); 
				diag_sc.prp_con_times ++ ;
			}
			else
			{
				diag_sc.prp_state = 1;
				diag_sc.prp_recv_cnt = 0;
				event_add_to_sram(EVT_ID_FT_SC , 0 , 0);
				sc_times = param_get_data(PAR_ID_SC_PRP_TIMES) + 1;
				param_set_data(PAR_ID_SC_PRP_TIMES , sc_times);
				if(diag_sc.prp_con_times == DIAG_SC_LOCK_TIMES)
				{
					event_add_to_sram(EVT_ID_SC_LOCK ,diag_sc.prp_con_times - 2 , DIAG_SC_LOCK_TIMES);
				}
				
				wifi_send_flag = 1;
			}
        }
		
		if((FALSE == dev_afe_read_sc_alarm()) && (var_get_data(VAR_ID_MOS_STATE) & (1 << VAR_MOS_ST_DSG)))
		{
			diag_sc.prp_con_times = 0;
		}
    }
    else
    {
        if((CURR_DR_CHG == sys_state)||1 == var_get_data(VAR_ID_FAULT_CLEAR_STATE))
        {
            diag_sc.prp_state = 0;
            diag_sc.prp_con_times = 0;
			sample_clr_sc_prp();
			diag_sc.prp_recv_cnt = 0;
			var_set_data(VAR_ID_FAULT_CLEAR_STATE , 0);
//			var_set_data(VAR_ID_FAULT_CLEAR_CNT , 0);				
        }
        else
        {
            if(diag_sc.prp_con_times < DIAG_SC_LOCK_TIMES)
            {
                diag_sc.prp_recv_cnt += cylce;
                if(diag_sc.prp_recv_cnt >= DIAG_SC_RCV_DLY)
                {
                    diag_sc.prp_state = 0;
                    sample_clr_sc_prp(); 
					++ diag_sc.prp_con_times;
					event_add_to_sram(EVT_ID_SC_TRY , diag_sc.prp_con_times - 2 , DIAG_SC_LOCK_TIMES);
                    diag_sc.prp_recv_cnt = 0;
                }
            }
			else
			{

			}
        }
    }

    diag_set_prp(PRP_ID_SC , diag_sc.prp_state);
}

/**
 * @brief  MOS故障诊断
 * @param  cylce : 周期
 */
void diag_sys_ft_mos(uint16_t cylce)
{
	float bur_curr = 0;
	uint16_t max_volt = 0;
	uint16_t avg_volt = 0;
	uint8_t cmos_state = 0;
	uint8_t dmos_state = 0;
	
	max_volt = var_get_data(VAR_ID_MAX_CELL_VOLT);
	avg_volt = var_get_data(VAR_ID_AGV_VOLT);
	bur_curr = var_get_data(VAR_ID_BUS_CURR) * VAR_CURR_FACTOR - VAR_CURR_OFFSET;

	if(var_get_data(VAR_ID_MOS_STATE) & (1 << VAR_MOS_ST_CHG))
		cmos_state = 1;
	if(var_get_data(VAR_ID_MOS_STATE) & (1 << VAR_MOS_ST_DSG))
		dmos_state = 1;
	
	if(0 == diag_ft_cmos.prp_state)
	{
		// 条件1：充电MOS必须处于断开状态且未处于限流状态
		// 条件2：
		//    有充电电流且充电电流大于3A，未开启充电限流最高单体电压大于3.400V或总电压持续上升持续10S。
		//    或最高单体电压大于3.45V，总电压电压持续上升持续10S。       
		if((0 == cmos_state) && (If_do_get_out_state(DO_LIMIT_10A) == DO_OUT_OFF))
		// (max_volt >= 3400) && (bur_curr > 3.0f) && (If_do_get_out_state(DO_LIMIT_10A) == DO_OUT_OFF))
		{
			if((bur_curr > 3.0f) && ((avg_volt >= 3450)||diag_get_prp(PRP_ID_OTM))) // 电流>3.0且最高单体电压高于3.450
			{
				diag_ft_cmos.prp_time_cnt += cylce;
				if(diag_ft_cmos.prp_time_cnt >= 10000)
				{
					
					diag_ft_cmos.prp_state = 1;				
					event_add_to_sram(EVT_ID_FT_CMOS , max_volt , var_get_data(VAR_ID_BUS_CURR));
					wifi_send_flag = 1;
					ctrl_prp_sec_spro();
				}
			}
			else if((avg_volt > 3500) && (bur_curr > 0) && (max_volt > (param_get_data(PAR_ID_COV_PRP_VAL) + 50))) // 有充电电流 
			{
				diag_ft_at_cmos.prp_time_cnt += cylce;
				if(diag_ft_at_cmos.prp_time_cnt >= 30000)
				{
					diag_ft_cmos.prp_state = 1;
					event_add_to_sram(EVT_ID_FT_CMOS , max_volt , var_get_data(VAR_ID_BUS_CURR));
					
					wifi_send_flag = 1;
                    ctrl_prp_sec_spro();
				}
			}
			else
			{
				diag_ft_cmos.prp_time_cnt = 0;
				diag_ft_at_cmos.prp_time_cnt =0;

			}
		}
		else
		{
			diag_ft_cmos.prp_time_cnt = 0;
			diag_ft_at_cmos.prp_time_cnt =0;
		}
	}
	
    diag_set_prp(PRP_ID_FT_CMOS , diag_ft_cmos.prp_state);
	
	if(0 == diag_ft_dmos.prp_state)
	{
		// 条件1：放电MOS必须处于断开状态
		// 条件2：放电电流大于3A，且平均电压低于3.0V 
		if((0 == dmos_state) && (avg_volt <= 3000) && (bur_curr < -3.0f))
		{
			diag_ft_dmos.prp_time_cnt += cylce;
			if(diag_ft_dmos.prp_time_cnt >= 10000)
			{
				diag_ft_dmos.prp_state = 1;
				event_add_to_sram(EVT_ID_FT_DMOS , max_volt , var_get_data(VAR_ID_BUS_CURR));
				wifi_send_flag = 1;
			}
		}
		else
		{
			diag_ft_dmos.prp_time_cnt = 0;
		}
	}
	

    diag_set_prp(PRP_ID_FT_DMOS , diag_ft_dmos.prp_state);
}

/**
 * @brief SOC过低诊断
 * @param  cylce:周期
 */
void diag_soc_alm(uint16_t cycle)  
{
    diag_para_type diag_para = {0};

	float smp_val = var_get_data(VAR_ID_DISP_SOC) * 0.01;
	uint8_t sys_state = 0;

	sys_state = var_get_data(VAR_ID_CURR_DR);	
	diag_data_type *p_data = &diag_soc_low;
 

    diag_para.alm_param = param_get_data(PAR_ID_SOCL_ALM_VAL);
    diag_para.alm_recv = param_get_data(PAR_ID_SOCL_ALM_RCV);
    diag_para.alm_dly = param_get_data(PAR_ID_SOCL_ALM_DLY);
	
    /* 告警诊断*/
    if((0 == p_data->alm_state)&&(CURR_DR_CHG != sys_state))
    {
        if(smp_val <= diag_para.alm_param)
        {
            p_data->alm_time_cnt += cycle;
            if(p_data->alm_time_cnt >= diag_para.alm_dly) 
            {
                p_data->alm_state = 1;
                p_data->alm_time_cnt = 0;
            }    
        }
        else
        {
            p_data->alm_time_cnt = 0;
        }
    }
    else
    {
        if((smp_val > diag_para.alm_recv)||(CURR_DR_CHG == sys_state))
        {
            p_data->alm_state = 0;
            p_data->alm_time_cnt = 0;
        }
    }
    diag_set_alarm(ALM_ID_SOCL , p_data->alm_state);
}

/** ------------------------------------------------------------------------- *
  *                              Local function
 ** ------------------------------------------------------------------------- */
 
/********** Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD *********/
